﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;

namespace OMSService
{
    public class UserManager
    {
        enum Conditions {Equals, NotEqual, Starts, Contains, NotContains, None};

        private static Conditions strToCondition(string str)
        {
            Conditions condition;
            switch (str)
                {
                    case "equal":
                        condition = Conditions.Equals;
                        break;
                    case "notequal":
                        condition = Conditions.NotEqual;
                        break;
                    case "starts":
                        condition = Conditions.Starts;
                        break;
                    case "contains":
                        condition = Conditions.Contains;
                        break;
                    case "notcontains":
                        condition = Conditions.NotContains;
                        break;
                    default:
                        condition = Conditions.None;
                        break;
                }
            return condition;
        }

        #region CRUD

        public static UserModel New(string login, string firstName, string lastName,
            string email, string password, string region, string role)
        {
            UserModel userModel = new UserModel(login, firstName, lastName, email, password,
                region, role);
            return userModel;
        }

        public static bool Save(UserModel userModel)
        {
            string salt = UserModel.GenerateSalt();
            try
            {
                using (OMSModelContainer context = new OMSModelContainer())
                {
                    Role role = (from m in context.Roles where m.UserRole == userModel.Role select m).FirstOrDefault();
                    if (role == null)
                    {
                        Helpers.CreateRoles();
                        role = (from m in context.Roles where m.UserRole == userModel.Role select m).FirstOrDefault();
                    }
                    User user = new User
                    {
                        Login = userModel.Login,
                        FirstName = userModel.FirstName,
                        LastName = userModel.LastName,
                        Email = userModel.Email,
                        Hash = UserModel.MakeHash(userModel.Password,salt),
                        Salt = salt,
                        Region = userModel.Region,
                        Role = role,
                        IsLocked = false
                    };
                    if(role.UserRole == "customer")
                    {
                        Customer customer = new Customer
                        {
                            Balance = 0,
                            Type = "default"
                        };
                        user.Customer = customer;
                    }
                    context.Users.AddObject(user);
                    context.SaveChanges();
                }
            }
            catch (DataException ex)
            {
                return false;
            }
            return true;
        }

        public static bool Create(string login, string firstName, string lastName,
            string email, string password, string region, string role)
        {
            UserModel userModel = New(login, firstName, lastName, email, password, region, role);
            return (Save(userModel));
        }

        public static bool Update(UserModel userModel)
        {
            try
            {
                using (OMSModelContainer context = new OMSModelContainer())
                {
                    User user = (from m in context.Users where m.Id == userModel.Id select m).First();
                    user.FirstName = userModel.FirstName;
                    user.LastName = userModel.LastName;
                    user.Email = userModel.Email;
                    user.Hash = UserModel.MakeHash(userModel.Password, user.Salt);
                    user.Region = userModel.Region;
                    context.Users.ApplyCurrentValues(user);
                    context.SaveChanges();
                }
            }
            catch (DataException)
            {
                return false;
            }
            return true;
        }

        public static bool Delete(int id)
        {
            //TODO: Test
            try
            {
                using (OMSModelContainer context = new OMSModelContainer())
                {
                    User user = (from m in context.Users where m.Id == id select m).First();
                    user.IsLocked = true;
                    context.Users.ApplyCurrentValues(user);
                    context.SaveChanges();
                }
            }
            catch (DataException)
            {
                return false;
            }
            return true;
        }

        public static int CheckPass(string userName, string password)
        {
            int userId = -1;
            try
            {
                using (OMSModelContainer context = new OMSModelContainer())
                {
                    User user = (from m in context.Users where m.Login == userName select m).FirstOrDefault();
                    if (user.Hash == UserModel.MakeHash(password, user.Salt))
                    {
                        userId = user.Id;
                    }
                }
            }
            catch (DataException)
            {
                return -1;
            }
            return userId;
        }

        #region Get

        public static UserModel GetById(int id)
        {
            User user;
            UserModel userModel;
            using (OMSModelContainer context = new OMSModelContainer())
            {
                user = (from m in context.Users where m.Id == id select m).First();
                userModel = new UserModel(user);
            }
            return userModel;
        }

        public static List<UserModel> GetAll()
        {
            List<User> users;
            List<UserModel> userModels = new List<UserModel>();
            using (OMSModelContainer context = new OMSModelContainer())
            {
                users = context.Users.ToList();
                foreach (User i in users)
                {
                    userModels.Add(new UserModel(i));
                }
            }
            return userModels;
        }
        #endregion

        #endregion

        #region Filters

        public static List<UserModel> Filter(string field, string strCondition, string pattern)
        {
            field = field.ToLower();
            strCondition = strCondition.ToLower();
            pattern = pattern.ToLower();
            Conditions condition = strToCondition(strCondition);
            List<UserModel> userModels = new List<UserModel>();                
                switch (field)
                {
                    case "all":
                        userModels = FilterByUserName(condition, pattern);
                        break;
                    case "username":
                        userModels = FilterByUserName(condition, pattern);
                        break;
                    case "firstname":
                        userModels = FilterByFirstName(condition, pattern);
                        break;
                    case "lastname":
                        userModels = FilterByLastName(condition, pattern);
                        break;
                    case "role":
                        userModels = FilterByRole(condition, pattern);
                        break;
                }
            return userModels;
        }

        private static List<UserModel> FilterByRole(Conditions condition, string role)
        {
            List<User> users = new List<User>();
            List<UserModel> userModels = new List<UserModel>();
            using (OMSModelContainer context = new OMSModelContainer())
            {
                switch (condition)
                {
                    case Conditions.Equals:
                        users = context.Users.Where(s => s.Role.UserRole.ToLower().Equals(role)).ToList();
                        break;
                    case Conditions.NotEqual:
                        users = context.Users.Where(s => !s.Role.UserRole.ToLower().Equals(role)).ToList();
                        break;
                    case Conditions.Starts:
                        users = context.Users.Where(s => s.Role.UserRole.ToLower().StartsWith(role)).ToList();
                        break;
                    case Conditions.Contains:
                        users = context.Users.Where(s => s.Role.UserRole.ToLower().Contains(role)).ToList();
                        break;
                    case Conditions.NotContains:
                        users = context.Users.Where(s => !s.Role.UserRole.ToLower().Contains(role)).ToList();
                        break;
                }
                foreach (User user in users)
                {
                    userModels.Add(new UserModel(user));
                }
            }
            return userModels;
        }

        private static List<UserModel> FilterByAll(Conditions condition, string pattern)
        {
            List<User> users = new List<User>();
            List<UserModel> userModels = new List<UserModel>();
            using (OMSModelContainer context = new OMSModelContainer())
            {
                switch (condition)
                {
                    case Conditions.Equals:
                        users = context.Users.Where(s => s.Login.ToLower().Equals(pattern) || 
                            s.FirstName.ToLower().Equals(pattern) ||
                            s.LastName.ToLower().Equals(pattern)).ToList();
                        break;
                    case Conditions.NotEqual:
                        users = context.Users.Where(s => !(s.Login.ToLower().Equals(pattern) ||
                            s.FirstName.ToLower().Equals(pattern) ||
                            s.LastName.ToLower().Equals(pattern))).ToList();
                        break;
                    case Conditions.Starts:
                        users = context.Users.Where(s => s.Login.ToLower().StartsWith(pattern) ||
                            s.FirstName.ToLower().StartsWith(pattern) ||
                            s.LastName.ToLower().StartsWith(pattern)).ToList();
                        break;
                    case Conditions.Contains:
                        users = context.Users.Where(s => s.Login.ToLower().Contains(pattern) ||
                            s.FirstName.ToLower().Contains(pattern) ||
                            s.LastName.ToLower().Contains(pattern)).ToList();
                        break;
                    case Conditions.NotContains:
                        users = context.Users.Where(s => !(s.Login.ToLower().Contains(pattern) ||
                            s.FirstName.ToLower().Contains(pattern) ||
                            s.LastName.ToLower().Contains(pattern))).ToList();
                        break;
                }
                foreach (User user in users)
                {
                    userModels.Add(new UserModel(user));
                }
            }
            return userModels;
        }

        private static List<UserModel> FilterByLastName(Conditions condition, string lastName)
        {
            lastName = lastName.ToLower();
            List<User> users = new List<User>();
            List<UserModel> userModels = new List<UserModel>();
            using (OMSModelContainer context = new OMSModelContainer())
            {
                switch (condition)
                {
                    case Conditions.Equals:
                        users = context.Users.Where(s => s.LastName.ToLower().Equals(lastName)).ToList();
                        break;
                    case Conditions.NotEqual:
                        users = context.Users.Where(s => !s.LastName.ToLower().Equals(lastName)).ToList();
                        break;
                    case Conditions.Starts:
                        users = context.Users.Where(s => s.LastName.ToLower().StartsWith(lastName)).ToList();
                        break;
                    case Conditions.Contains:
                        users = context.Users.Where(s => s.LastName.ToLower().Contains(lastName)).ToList();
                        break;
                    case Conditions.NotContains:
                        users = context.Users.Where(s => !s.LastName.ToLower().Contains(lastName)).ToList();
                        break;
                }
                foreach (User user in users)
                {
                    userModels.Add(new UserModel(user));
                }
            }
            return userModels;
        }

        private static List<UserModel> FilterByFirstName(Conditions condition, string firstName)
        {
            List<User> users = new List<User>();
            firstName = firstName.ToLower();
            List<UserModel> userModels = new List<UserModel>();
            using (OMSModelContainer context = new OMSModelContainer())
            {
                switch (condition)
                {
                    case Conditions.Equals:
                        users = context.Users.Where(s => s.FirstName.ToLower().Equals(firstName)).ToList();
                        break;
                    case Conditions.NotEqual:
                        users = context.Users.Where(s => !s.FirstName.ToLower().Equals(firstName)).ToList();
                        break;
                    case Conditions.Starts:
                        users = context.Users.Where(s => s.FirstName.ToLower().StartsWith(firstName)).ToList();
                        break;
                    case Conditions.Contains:
                        users = context.Users.Where(s => s.FirstName.ToLower().Contains(firstName)).ToList();
                        break;
                    case Conditions.NotContains:
                        users = context.Users.Where(s => !s.FirstName.ToLower().Contains(firstName)).ToList();
                        break;
                }
                foreach (User user in users)
                {
                    userModels.Add(new UserModel(user));
                }
            }
            return userModels;
        }

        private static List<UserModel> FilterByUserName(Conditions condition, string userName)
        {
            List<User> users = new List<User>();
            List<UserModel> userModels = new List<UserModel>();
            using (OMSModelContainer context = new OMSModelContainer())
            {
                switch (condition)
                {
                    case Conditions.Equals:
                        users = context.Users.Where(s => s.Login.ToLower().Equals(userName)).ToList();
                        break;
                    case Conditions.NotEqual:
                        users = context.Users.Where(s => !s.Login.ToLower().Equals(userName)).ToList();
                        break;
                    case Conditions.Starts:
                        users = context.Users.Where(s => s.Login.ToLower().StartsWith(userName)).ToList();
                        break;
                    case Conditions.Contains:
                        users = context.Users.Where(s => s.Login.ToLower().Contains(userName)).ToList();
                        break;
                    case Conditions.NotContains:
                        users = context.Users.Where(s => !s.Login.ToLower().Contains(userName)).ToList();
                        break;
                }
                foreach (User user in users)
                {
                    userModels.Add(new UserModel(user));
                }
            }
            return userModels;
        }
        #endregion
    }
}